home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / workbench werkzeuge / uhren & terminkalender / time / ledclock / leds.c < prev    next >
C/C++ Source or Header  |  1996-04-07  |  11KB  |  347 lines

  1. /* LedClock (C)1987 Ali T. Ozer. A clock program for interlaced screens. */
  2.  
  3. #include <exec/types.h>
  4. #include <functions.h>
  5. #include <intuition/intuition.h>
  6. #include <exec/devices.h>
  7. #include <devices/timer.h>
  8. #include <graphics/gfxmacros.h>
  9.  
  10. /* LedClock is freely distributable and NOT for sale. 
  11. **
  12. ** Author: Ali T. Ozer, ARPA: ali@score.stanford.edu, 
  13. **                      REAL: Box 7703, Stanford, CA 94309
  14. **
  15. ** A clock program for interlaced screens. This one uses
  16. ** numbers that resemble the numbers used in 7-segment LED and LCD
  17. ** clock displays. Various options are provided as compile time "#define"s:
  18. **  
  19. ** TWENTYFOURHOUR  0 or 1, determines if the clock is 24-hour or not
  20. ** WINDOWXLOC      starting X location for the window in the WB screen
  21. ** WINDOWYLOC      starting Y location for the window in the WB screen
  22. ** FANCYPANIC      0 or 1, determines if a error message box is shown in
  23. **                 case the clock can't run...
  24. **
  25. ** LedClock works best with interlaced screens --- It will look ugly on a 
  26. ** "normal" WorkBench screen. (It will probably look fine on a lo-res, non
  27. ** interlaced screen, except it will be too big, way too big.)
  28. **
  29. ** LedClock can be compiled by Manx 3.40a. Use the "+c" and "+d" switches
  30. ** while linking to assure that the static images go into CHIP ram:
  31. **
  32. **   cc ledclock.c
  33. **   ln +cd ledclock.o -lc
  34. **   run ledclock
  35. **
  36. ** During linking you'll get warnings about _cli_parse and _wb_parse being
  37. ** redefined; you can safely ignore these messages.
  38. **
  39. ** Various corners have been cut from this program to make the executable small.
  40. ** With Manx 3.40a, the executable is somewhere around 3.1 Kbytes. One can
  41. ** probably achieve half that size in assembly.
  42. **
  43. ** Programmers might wish to fool around with the code to customize the
  44. ** clock. It's amazing how many parameters one can think of if one tries
  45. ** to make a general program... So, rather than trying to provide zillions
  46. ** of command line arguments, I took the easy way out and just threw out
  47. ** all generality... If you wish to create your customized clocks from
  48. ** this code, feel free to do so --- but please keep my original copyright
  49. ** notice (in the screen title bar) intact, along with any additional
  50. ** copyright notices you might add.
  51. */
  52.  
  53. /* The next few define's can be changed for different runtime parameters... */
  54.  
  55. #define TWENTYFOURHOUR 1
  56. #define FANCYPANIC     0
  57. #define WINDOWXLOC     20
  58. #define WINDOWYLOC     14
  59.  
  60. #define COPYRIGHT "LedClock 1.0 (C)1987 Ali T. Ozer"
  61.  
  62. #if FANCYPANIC
  63. #define Panic(arg)  WarnUser(arg)
  64. #else 
  65. #define Panic(arg)  CloseThings(1)
  66. #endif
  67.  
  68. #define DIGITMAXX 18
  69. #define DIGITMAXY 32
  70.  
  71. #define WINDOWX 0
  72. #define WINDOWY 9
  73. #define DIGIT1X (WINDOWX + 3)
  74. #define DIGIT2X (DIGIT1X + DIGITMAXX + 3)
  75. #define DIGIT3X (DIGIT2X + DIGITMAXX + 10)
  76. #define DIGIT4X (DIGIT3X + DIGITMAXX + 3)
  77. #define DIGITY  (WINDOWY + 3)
  78. #define WINDOWWIDTH  (DIGIT4X + DIGITMAXX + 3)
  79. #define WINDOWHEIGHT (DIGITY + DIGITMAXY + 3)
  80. #define COLONX  (DIGIT3X - 6)
  81. #define COLONY  (DIGITY  + 11)
  82.  
  83. /* The "leds" (the segments making up the digits) are named in the standard
  84. ** (clockwise) fashion, with a = top led, b = right top, ... f = left top, and
  85. ** g = middle.
  86. **
  87. ** The following describes the vertical leds ("b", "c", "e", and "f") 
  88. */
  89. USHORT vled [] = {
  90.  0xdfff, 0x8fff, 0x8fff, 0x8fff, 0x8fff, 0x8fff, 0x8fff,
  91.  0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0xbfff 
  92. };
  93.  
  94. /* The following is the bitmap description of leds a and d.
  95. */
  96. USHORT hled [] = {0x807f, 0x003f, 0x807f};
  97.  
  98. /* The following is the bitmap description of the middle ("g") led.
  99. */
  100. USHORT mled [] = {0x80ff, 0x007f, 0x80ff};
  101.  
  102. /* The following describes the bitmap for the colon and the image.
  103. */
  104. USHORT colondata [] = {
  105. 0x8fff, 0x8fff, 0x8fff, 0xffff, 0xffff, 0xffff,
  106. 0xffff, 0xffff, 0x1fff, 0x1fff, 0x1fff
  107. };
  108.  
  109. struct Image colon = { 0,  0,  4, 11, 1, colondata, 1, 0, NULL};
  110.  
  111. /* The following describes the Image structures for all 7 leds, "a".."g"
  112. */
  113. struct Image leds [] = {
  114. { 6,  0, 10,  3, 1, &hled[0], 1, 0, NULL},
  115. {15,  2,  4, 14, 1, &vled[0], 1, 0, NULL},
  116. {13, 17,  4, 14, 1, &vled[0], 1, 0, NULL},
  117. { 3, 30, 10,  3, 1, &hled[0], 1, 0, NULL},
  118. { 0, 17,  4, 14, 1, &vled[0], 1, 0, NULL},
  119. { 2,  2,  4, 14, 1, &vled[0], 1, 0, NULL},
  120. { 5, 15,  9,  3, 1, &mled[0], 1, 0, NULL}
  121. };
  122.  
  123. /* In the following each byte determines what leds are lit for the 
  124. ** corresponding digit. The bits are ordered "xgfedcba" and a 1 means the 
  125. ** led is lit.
  126. */
  127. UBYTE lled [] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
  128.  
  129. struct Window      *MyWin;
  130. struct RastPort    *MyRP;
  131. struct Library     *IntuitionBase;
  132. struct Library     *GfxBase;
  133. struct timerequest  MyTR;
  134. unsigned long      WindowSig, TimerSig;
  135. int                curminutes;
  136.  
  137. /* Draw digit puts a 7-segment digit at the specified location. If digit is
  138. ** negative, then the area is erased but nothing is drawn. 
  139. */
  140. DrawDigit (rp, digit, xloc, yloc)
  141. struct RastPort *rp;
  142. int digit, xloc, yloc;
  143. {
  144.   register int ledmask, ledcnt = 0;
  145.   
  146.   /* First erase it */
  147.   RectFill (rp, (long)xloc, (long)yloc, 
  148.                 (long)(xloc + DIGITMAXX), (long)(yloc + DIGITMAXY));
  149.  
  150.   if (digit >= 0) {
  151.     ledmask = lled[digit];
  152.     while (ledcnt != 7) {
  153.       if (ledmask & 1) DrawImage (rp, &leds[ledcnt], (long)xloc, (long)yloc);
  154.       ledcnt++; ledmask >>= 1;
  155.     }
  156.   }
  157. }
  158.  
  159. /* OpenTimer will open the timer device and also do all the initialization
  160. ** necessary to send timer requests... 
  161. */
  162. OpenTimer (tr)
  163. struct timerequest *tr;
  164. {
  165.   struct MsgPort *timerport;
  166.  
  167.   while ((timerport = CreatePort (NULL, 0L)) == NULL) Panic ("No port");
  168.  
  169.   OpenDevice (TIMERNAME, UNIT_VBLANK, tr, 0L);
  170.   tr->tr_node.io_Message.mn_ReplyPort = timerport;
  171.   tr->tr_node.io_Command = TR_ADDREQUEST;
  172.  
  173. }
  174.  
  175. /* OpenThings opens the Amiga libraries, the window. and the timer.
  176. ** If something goes wrong, a requester will pop up to warn the user.
  177. ** (If FANCYPANIC is defined as zero, then no requester pops up --- the
  178. ** program just quits.)
  179. */
  180. OpenThings ()
  181. {
  182.   static struct NewWindow MyWinInfo =
  183.   { WINDOWXLOC, WINDOWYLOC, WINDOWWIDTH, WINDOWHEIGHT, /* Lft,Top,Wd,Hgt */
  184.     -1,-1,                   /* Detail pen, Block pen (-1 = use screens) */
  185.     CLOSEWINDOW,                                           /* IDCMPflags */
  186.     SMART_REFRESH | WINDOWDEPTH | WINDOWDRAG | WINDOWCLOSE | NOCAREREFRESH,
  187.     NULL, NULL, NULL,              /* FirstGadget, Menu Checkmark, Title */
  188.     NULL, NULL,                                        /* Screen, Bitmap */
  189.     0, 0, 0, 0,                     /* Min Width/Height Max Width/Height */
  190.     WBENCHSCREEN                                                 /* Type */
  191.   };
  192.  
  193.   if (((IntuitionBase = OpenLibrary("intuition.library",0L)) == NULL) ||
  194.       ((GfxBase = OpenLibrary("graphics.library",0L)) == NULL)) CloseThings (1);
  195.  
  196.   while (!(MyWin = OpenWindow(&MyWinInfo))) Panic ("No window");
  197.   SetWindowTitles (MyWin, NULL, COPYRIGHT);
  198.  
  199.   MyRP = MyWin->RPort;
  200.   WindowSig = 1L << MyWin->UserPort->mp_SigBit;
  201.  
  202.   SetOPen (MyRP, 1L); 
  203.   SetAPen (MyRP, 1L);
  204.  
  205.   OpenTimer(&MyTR);
  206.   TimerSig = 1L << MyTR.tr_node.io_Message.mn_ReplyPort->mp_SigBit;
  207. }  
  208.  
  209. /* SendTimerRequest sends a timer request for the indicated amount of seconds.
  210. ** Assumes the timer request block pointed to by tr has already been properly
  211. ** setup --- including the io_Command field. 
  212. */
  213. SendTimerRequest (tr, seconds)
  214. struct timerequest *tr;
  215. unsigned long seconds;
  216. {
  217.   tr->tr_time.tv_micro = 0L;
  218.   tr->tr_time.tv_secs  = seconds;
  219.   SendIO (tr);
  220. }
  221.   
  222. #if FANCYPANIC
  223.  
  224. /* WarnUser is called when something goes wrong during initialization.
  225. ** WarnUser assumes Intuition is opened! (Now if that's not the case,
  226. ** then you're in trouble...)
  227. */
  228.  
  229. WarnUser (reason)
  230. UBYTE *reason;
  231. {
  232.   static struct IntuiText postxt  = {3,1,COMPLEMENT,4,4,NULL,(UBYTE *)"Retry",NULL};
  233.   static struct IntuiText negtxt  = {3,1,COMPLEMENT,4,4,NULL,(UBYTE *)"Sigh",NULL};
  234.   static struct IntuiText bodytxt = {3,1,COMPLEMENT,4,6,NULL,NULL,NULL};
  235.  
  236.   bodytxt.IText = reason;
  237.   if (AutoRequest (NULL,&bodytxt,&postxt,&negtxt,0L,0L,300L,60L) == FALSE)
  238.      CloseThings (1);
  239. }
  240.  
  241. #endif
  242.  
  243. /* CloseTimer closes the timer pointed to by tr. If no reply port is present,
  244. ** then CloseTimer assumes the timer was never opened.
  245. */
  246. CloseTimer (tr)
  247. struct timerequest *tr;
  248. {
  249.   struct MsgPort *msgp;
  250.   if (msgp = tr->tr_node.io_Message.mn_ReplyPort) {
  251.     DeletePort (msgp);  
  252.     CloseDevice (tr);
  253.   }
  254. }
  255.  
  256. /* CloseThings releases all the resources obtained by the program.
  257. */
  258. CloseThings(error_code)
  259. int error_code;
  260.   CloseTimer(&MyTR);
  261.   if (MyWin)         CloseWindow(MyWin);
  262.   if (GfxBase)       CloseLibrary(GfxBase);
  263.   if (IntuitionBase) CloseLibrary(IntuitionBase);
  264.   exit (error_code);
  265. }
  266.  
  267. static int ht = -1, ho = -1, mt = -1, mo = -1;
  268.  
  269. /* WriteTime writes out the new time. 
  270. */
  271. WriteTime (minutes)
  272. int minutes;
  273. {
  274.   int hours, htens, hones, mtens, mones;
  275.   
  276. #if TWENTYFOURHOUR
  277.   hours = minutes / 60;
  278. #else
  279.   hours = (minutes / 60 + 11) % 12 + 1;
  280. #endif
  281.     
  282.   /* AM if minutes < 720, but we don't worry about this... */
  283.  
  284.   if ((htens = hours / 10) != ht)
  285.     DrawDigit (MyRP, ((ht = htens) ? ht : -1), DIGIT1X, DIGITY);
  286.   if ((hones = hours % 10) != ho)
  287.     DrawDigit (MyRP, ho = hones, DIGIT2X, DIGITY);
  288.   if ((mtens = (minutes % 60) / 10) != mt)
  289.     DrawDigit (MyRP, mt = mtens, DIGIT3X, DIGITY);
  290.   if ((mones = (minutes % 10)) != mo)
  291.     DrawDigit (MyRP, mo = mones, DIGIT4X, DIGITY);
  292. }    
  293.  
  294. /* ShowTheTime reads the time, updates the display, and sends a new timer
  295. ** request.
  296. */
  297. ShowTheTime ()
  298. {
  299.   long timevec[3];
  300.  
  301.   DateStamp (&timevec[0]);
  302.   curminutes = (int)(timevec[1]);
  303.   WriteTime (curminutes);
  304.   /* Timer request for the next top of minute */
  305.   SendTimerRequest (&MyTR, 60L - (long)(timevec[2] / 50L));
  306. }
  307.  
  308. main ()
  309. {
  310.   struct Task *me;
  311.  
  312.   OpenThings  ();
  313.  
  314.   /* Bump the priority up to 5. Not too serious, as under normal conditions
  315.   ** this program will wake up only every 60 seconds.
  316.   */
  317.   if (me = FindTask (NULL)) SetTaskPri (me, 5L); 
  318.  
  319.   /* Clear the window and draw in the ":". 
  320.   */  
  321.   RectFill  (MyRP, (long)WINDOWX, (long)WINDOWY, 
  322.                     WINDOWWIDTH-1L, WINDOWHEIGHT-1L); 
  323.   DrawImage (MyRP, &colon, (long)COLONX, (long)COLONY);
  324.  
  325.   /* Now sit down, relax, and wait for either an IDCMP or a timer event...
  326.   */
  327.   while (1) {
  328.     ShowTheTime ();
  329.     if (Wait (WindowSig | TimerSig) & TimerSig)
  330.        (void) GetMsg (MyTR.tr_node.io_Message.mn_ReplyPort);
  331.     else {  
  332.        AbortIO (&MyTR);  /* Don't even get the message, assume it's CLOSEWINDOW */
  333.        CloseThings (0);
  334.     }
  335.   }
  336. }
  337.  
  338.  
  339.  
  340. /* Including the following two lines prevents the linker from bringing in
  341. ** the two functions _wb_parse and _cli_parse called by the initialization
  342. ** code in _main. Reduces code size by about 900 bytes for Manx 3.40a.
  343. */
  344. void _wb_parse () {}
  345. void _cli_parse () {}
  346.